package com.net.xpay.core.service.impl.safePay;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.domain.collect.CollectionSafePayChannel;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.constant.TransBizTypeConstant;
import com.net.xpay.core.enums.CollectionSafePayOrderStatus;
import com.net.xpay.core.enums.PayeeType;
import com.net.xpay.core.enums.SafePayBatchStatus;
import com.net.xpay.core.enums.SafePayOrderStatus;
import com.net.xpay.core.model.*;
import com.net.xpay.core.service.safePay.CollectionSafePayService;
import com.net.xpay.core.service.safePay.SafePayService;
import com.net.xpay.core.validator.CollectionSafePayOrderValidator;
import com.net.common.annotation.WriteTransactional;
import com.net.common.exception.BusinessException;
import com.net.common.util.StreamUtil;
import com.net.xpay.alipay.enums.IdentityType;
import com.net.xpay.common.manager.collect.CollectionSafePayChannelManager;
import com.net.xpay.core.CoreProperties;

import com.net.xpay.core.domain.collect.CollectionSafePayBatch;
import com.net.xpay.core.domain.collect.CollectionSafePayOrder;
import com.net.xpay.core.domain.safePay.SafePayBatch;
import com.net.xpay.core.domain.safePay.SafePayOrder;
import com.net.xpay.core.enums.*;
import com.net.xpay.core.helper.QrCodeHelper;
import com.net.xpay.core.manager.collect.CollectionSafePayBatchManager;
import com.net.xpay.core.manager.collect.CollectionSafePayOrderManager;
import com.net.xpay.core.manager.safePay.SafePayOrderManager;
import com.net.xpay.core.model.*;
import com.net.xpay.core.utils.UuidUtil;
import com.net.shard.ShardUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

@Slf4j
@Service
public class CollectionSafePayServiceImpl implements CollectionSafePayService {

    @Autowired
    private CoreProperties coreProperties;

    @Autowired
    private QrCodeHelper qrCodeHelper;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private CollectionSafePayChannelManager collectionSafePayChannelManager;

    @Autowired
    private CollectionSafePayOrderValidator collectionSafePayOrderValidator;

    @Autowired
    private CollectionSafePayOrderManager collectionSafePayOrderManager;

    @Autowired
    private CollectionSafePayBatchManager collectionSafePayBatchManager;

    @Autowired
    private SafePayService safePayService;

    @Autowired
    private SafePayOrderManager safePayOrderManager;

    @Override
    public CollectionSafePayChannel addCollectionSafePayChannel(User merchant, CreateCollectionSafePayChannelModel model) {
        if (model.getName() == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入渠道名称");
        }
        model.setName(model.getName().trim());
        if (Strings.isNullOrEmpty(model.getName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入渠道名称");
        }
        if (model.getName().length() > 128) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "渠道名称不能超过128个字");
        }
        if (!Strings.isNullOrEmpty(model.getRemark()) && model.getRemark().length() > 128) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "备注不能超过128个字");
        }
        CollectionSafePayChannel select = collectionSafePayChannelManager.findByName(merchant.getId(), model.getName());
        if (select != null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "渠道名称已被使用，请使用其他渠道名称");
        }

        CollectionSafePayChannel channel = new CollectionSafePayChannel();
        channel.setUserId(merchant.getId());
        channel.setName(model.getName());
        channel.setRemark(model.getRemark());
        channel.setUuid(UuidUtil.uuid());

        //生成二维码
        String url = "http://" + coreProperties.getMobileDomain() + "/#/collectSafePayOrder?uuid=" + channel.getUuid();
        try {
            String qrcode = qrCodeHelper.genThenUpload(url);
            channel.setQrCode(qrcode);
            channel.setUrl(url);
            collectionSafePayChannelManager.save(channel);
            return channel;
        } catch (IOException e) {
            log.error("addCollectionSafePayChannel error userId={}", merchant.getId(), e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "系统繁忙");
        }

    }

    @Override
    public CollectionSafePayChannel modifyCollectionSafePayChannelInfo(User merchant, ModifyCollectionSafePayChannelModel model) {
        Preconditions.checkArgument(model != null && model.getId() != null);
        if (model.getName() == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入渠道名称");
        }
        model.setName(model.getName().trim());
        if (Strings.isNullOrEmpty(model.getName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入渠道名称");
        }
        if (model.getName().length() > 128) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "渠道名称不能超过128个字");
        }
        if (!Strings.isNullOrEmpty(model.getRemark()) && model.getRemark().length() > 128) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "备注不能超过128个字");
        }
        CollectionSafePayChannel select = collectionSafePayChannelManager.findByName(merchant.getId(), model.getName());
        if (select != null && !select.getId().equals(model.getId())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "渠道名称已被使用，请使用其他渠道名称");
        }
        CollectionSafePayChannel channel = collectionSafePayChannelManager.findById(merchant.getId(), model.getId());
        channel.setName(model.getName());
        channel.setRemark(model.getRemark());
        collectionSafePayChannelManager.update(channel);
        return channel;
    }

    @Override
    public void deleteCollectionSafePayChannel(User merchant, IdModel model) {
        Preconditions.checkArgument(model != null && model.getId() != null);
        CollectionSafePayChannel channel = collectionSafePayChannelManager.findById(merchant.getId(), model.getId());
        if (channel == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "渠道不存在或已被删除");
        }
        collectionSafePayChannelManager.deleteById(model.getId());
    }

    @Override
    public CollectionSafePayOrder addCollectionSafePayOrder(CollectionSafePayOrderModel model) {
        collectionSafePayOrderValidator.validateAddCollectionSafePayOrder(model);

        CollectionSafePayChannel channel = collectionSafePayChannelManager.getByUuid(model.getUuid());

        Preconditions.checkArgument(channel.getUuid().equals(model.getUuid()));

        UserShard userShard = userShardManager.getById(channel.getUserId());
        try {
            ShardUtil.setShardContext(userShard.getShardId());
            CollectionSafePayOrder order = CollectionSafePayOrder.getInstance();
            order.setName(model.getName());
            order.setIdentity(model.getIdentity());
            order.setIdentityType(IdentityType.BANKCARD_ACCOUNT.getValue());
            order.setTransAmount(new BigDecimal(model.getTransAmount()));
            order.setUserId(channel.getUserId());
            order.setCollectionSafePayChannelId(channel.getId());
            order.setStatus(CollectionSafePayOrderStatus.INIT);
            collectionSafePayOrderManager.save(order);
            return order;
        } finally {
            ShardUtil.cleanShardContext();
        }
    }

    @Override
    @WriteTransactional
    public SafePayBatch createTransBatch(User merchant, CollectionSafePayOrderTransModel transModel) {
        if (CollectionUtils.isEmpty(transModel.getOrderIds())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "至少选择一个收款订单");
        }
        if (transModel.getOrderIds().size() > 1000) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "单次转账不能超过1000笔");
        }
        if (Strings.isNullOrEmpty(transModel.getAlipayNickName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请选择付款支付宝账号");
        }

        List<CollectionSafePayOrder> orders = new ArrayList<>();
        List<SafePayTransModel> payTransModels = new ArrayList<>();
        BigDecimal totalAmount = new BigDecimal(0);
        for (Long orderId : transModel.getOrderIds()) {
            CollectionSafePayOrder order = collectionSafePayOrderManager.getById(orderId);
            if (order == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款订单不存在");
            }
            if (order.getStatus() != CollectionSafePayOrderStatus.INIT && order.getStatus() != CollectionSafePayOrderStatus.FAIL) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款订单状态不为待转账状态 无法转账");
            }
            SafePayTransModel payTransModel = new SafePayTransModel();
            payTransModel.setImportBizNo(order.getId().toString());
            payTransModel.setTransAmount(order.getTransAmount().toString());
            payTransModel.setIdentity(order.getIdentity());
            payTransModel.setName(order.getName());
            payTransModels.add(payTransModel);

            totalAmount = totalAmount.add(order.getTransAmount());
            orders.add(order);
            order.setStatus(CollectionSafePayOrderStatus.DEALING);
            collectionSafePayOrderManager.updateByPrimaryKeyWithVersion(order);
        }

        //生成批次记录
        CollectionSafePayBatch batch = CollectionSafePayBatch.getInstance();
        batch.setUserId(merchant.getId());
        batch.setStatus(SafePayBatchStatus.WAIT_ENSURE);
        batch.setTotalTransAmount(totalAmount);
        batch.setTotalCount((long) orders.size());
        batch.setDealingTime(LocalDateTime.now());
        batch.setOrderIds(transModel.getOrderIds());
        collectionSafePayBatchManager.save(batch);

        //创建批次
        SafePayBatchCreateModel model = buildSafePayBatchCreateModel(batch.getBizId(), transModel.getAlipayNickName(), payTransModels);
        return safePayService.createSafePayBatch(merchant, model);
    }

    @Override
    @WriteTransactional
    public void closeCollectionSafePayBatchCallback(User user, SafePayBatch batch) {
        if (!batch.getImportBatchNo().startsWith(TransBizTypeConstant.CB_SP)) {
            log.error("closeCollectionSafePayBatchCallback error biz type wrong|importBatchNo={}|userId={}", batch.getImportBatchNo(), user.getId());
            return;
        }

        CollectionSafePayBatch collectionSafePayBatch = collectionSafePayBatchManager.findByBizId(user.getId(), batch.getImportBatchNo());

        collectionSafePayBatch.setStatus(SafePayBatchStatus.DISUSE);
        collectionSafePayBatch.setEndTime(LocalDateTime.now());
        collectionSafePayBatch.setSuccessAmount(batch.getSuccessAmount());
        collectionSafePayBatch.setFailedAmount(batch.getFailedAmount());
        collectionSafePayBatch.setSuccessCount(batch.getSuccessCount());
        collectionSafePayBatch.setFailCount(batch.getFailCount());
        collectionSafePayBatchManager.updateByPrimaryKeyWithVersion(collectionSafePayBatch);

        //订单重置为初始待打款状态
        collectionSafePayOrderManager.updateStatusByIds(CollectionSafePayOrderStatus.INIT.getValue(), collectionSafePayBatch.getOrderIds());
    }

    @Override
    @WriteTransactional
    public void updateCollectionSafePayBatch(User user, SafePayBatch batch) {
        log.info("updateCollectionSafePayBatch userId={}|safePaybatchId={}", user.getId(), batch.getId());
        if (!batch.getImportBatchNo().startsWith(TransBizTypeConstant.CB_SP)) {
            return;
        }
        if (batch.getEndTime() == null) {
            return;
        }

        CollectionSafePayBatch collectionBatch = collectionSafePayBatchManager.findByBizId(user.getId(), batch.getImportBatchNo());
        if (collectionBatch == null) {
            log.error("updateCollectionSafePayBatch error batch is not find userId={}|batchId={}", user.getId(), batch.getId());
            return;
        }

        collectionBatch.setSuccessCount(batch.getSuccessCount());
        collectionBatch.setSuccessAmount(batch.getSuccessAmount());
        collectionBatch.setFailCount(batch.getFailCount());
        collectionBatch.setFailedAmount(batch.getFailedAmount());
        collectionBatch.setEndTime(batch.getEndTime());
        collectionBatch.setStatus(batch.getStatus());
        collectionSafePayBatchManager.updateByPrimaryKeyWithVersion(collectionBatch);

        //重新查出来
        List<SafePayOrder> safePayOrders = safePayOrderManager.listByBatchId(batch.getUserId(), batch.getId());

        List<CollectionSafePayOrder> orders = collectionSafePayOrderManager.findByIds(collectionBatch.getOrderIds());

        Map<String/*importBizNo*/, SafePayOrder> payTransMap = StreamUtil.toMap(safePayOrders, SafePayOrder::getImportBizNo);
        for (CollectionSafePayOrder order : orders) {
            SafePayOrder payTrans = payTransMap.get(order.getId().toString());
            if (payTrans.getStatus() == SafePayOrderStatus.SUCCESS) {
                order.setStatus(CollectionSafePayOrderStatus.SUCCESS);
            } else {
                order.setStatus(CollectionSafePayOrderStatus.FAIL);
                order.setErrorCode(payTrans.getErrorCode());
                order.setErrorMsg(payTrans.getErrorMsg());
            }

            order.setEndTime(payTrans.getEndTime());
        }
        collectionSafePayOrderManager.batchUpdate(orders);
    }

    @Override
    public void deleteOrderById(User merchant, Long id) {
        Preconditions.checkArgument(id != null);
        CollectionSafePayOrder order = collectionSafePayOrderManager.findById(merchant.getId(), id);
        if (order == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "订单不存在");
        }
        if (order.getStatus() != CollectionSafePayOrderStatus.INIT && order.getStatus() != CollectionSafePayOrderStatus.FAIL) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "订单不是待转账或失败状态，无法删除");
        }
        order.setStatus(CollectionSafePayOrderStatus.DISUSE);
        order.setEndTime(LocalDateTime.now());
        collectionSafePayOrderManager.updateByPrimaryKeyWithVersion(order);
    }

    private SafePayBatchCreateModel buildSafePayBatchCreateModel(String batchId, String alipayNickName, List<SafePayTransModel> payTrans) {
        SafePayBatchCreateModel safePayBatchCreateModel = new SafePayBatchCreateModel();

        safePayBatchCreateModel.setPayTrans(payTrans);
        safePayBatchCreateModel.setImportBatchNo(batchId);
        safePayBatchCreateModel.setAlipayNickName(alipayNickName);
        safePayBatchCreateModel.setNeedNotify(false);
        safePayBatchCreateModel.setType(PayeeType.BANK);
        Function<SafePayTransModel, BigDecimal> sum = ins -> new BigDecimal(ins.getTransAmount());
        safePayBatchCreateModel.setTotalTransAmount(StreamUtil.sum(payTrans, sum).toString());
        safePayBatchCreateModel.setTotalCount((long) payTrans.size());

        return safePayBatchCreateModel;
    }
}
